package com.gr.staffpm.pages.projects;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;

import org.apache.wicket.ResourceReference;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.MarkupStream;
import org.apache.wicket.markup.html.IHeaderContributor;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.markup.html.WebComponent;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.parser.XmlTag;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.joda.time.DateTime;

import com.gr.staffpm.css.CssScope;
import com.gr.staffpm.datatypes.Project;
import com.gr.staffpm.datatypes.Task;
import com.gr.staffpm.js.StaffPMJSScope;
import com.gr.staffpm.tasks.service.TaskService;


public class TasksTabPanel extends Panel implements IHeaderContributor {

    @SpringBean(name = "taskService")
    private TaskService taskService;
    private static final long serialVersionUID = 1L;
    private final Project project;

    public TasksTabPanel(String id, Project p) {
        super(id);
        this.project = p;

        add(new WebComponent("ganttScript") {

            private static final long serialVersionUID = 1L;

            @Override
            protected void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag) {
                replaceComponentTagBody(markupStream, openTag, getGanttScript());
            }

            @Override
            protected void onComponentTag(ComponentTag tag) {
                super.onComponentTag(tag);
                // always transform the tag to <span></span> so even labels defined as <span/> render
                tag.setType(XmlTag.OPEN);
            }
        });
    }

    /* (non-Javadoc)
     * @see org.apache.wicket.markup.html.IHeaderContributor#renderHead(org.apache.wicket.markup.html.IHeaderResponse)
     */
    @Override
    public void renderHead(IHeaderResponse response) {
        /*response.renderCSSReference(new ResourceReference(CssScope.class, "extjs/ext-all.css"));
        response.renderCSSReference(new ResourceReference(CssScope.class, "extjs/Spinner.css"));
        response.renderCSSReference(new ResourceReference(CssScope.class, "extjs/LockingGridView.css"));*/
        response.renderCSSReference(new ResourceReference(CssScope.class, "extjs/sch-gantt-all.css"));
        response.renderJavascriptReference(new ResourceReference(StaffPMJSScope.class, "extjs/sch-gantt-base-debug.js"));
        response.renderJavascriptReference(new ResourceReference(StaffPMJSScope.class, "extjs/sch-gantt-all-debug.js"));
        /*response.renderJavascriptReference(new ResourceReference(StaffPMJSScope.class, "extjs/LockingGridView.js"));
        response.renderJavascriptReference(new ResourceReference(StaffPMJSScope.class, "extjs/Spinner.js"));
        response.renderJavascriptReference(new ResourceReference(StaffPMJSScope.class, "extjs/SpinnerField.js"));*/
        //response.renderJavascriptReference(new ResourceReference(TasksTabPanel.class, "gantt.js"));
    }

    /**
     * Returns Javascript code which renders the gantt chart.
     * @throws RuntimeException if gantt.js cannot be loaded.
     */
    private String getGanttScript() {
        try {
            final String str = getResourceContents(TasksTabPanel.class, "gantt.js");

            String tasks = tasksToString();

            return str.replace("%s", String.valueOf(project.getProjectId()));
        } catch (IOException e) {
            throw new RuntimeException("Unable to load gantt.js", e);
        }
    }

    /**
     * @return
     */
    private String tasksToString() {
        StringBuilder str = new StringBuilder();
        List<Task> tasks = taskService.getUnresolvedProjectTasks(project);
        str.append("'<Tasks>");
        DateTime start = new DateTime(project.getCreated());
        str.append("<Task>");
        str.append("<Id>1</Id>");
        str.append("<Name>" + project.getProjectName() + "</Name>");
        str.append("<StartDate>" + start.withTime(0, 0, 0, 0).toString() + "</StartDate>");
        str.append("<EndDate>" + new DateTime().plusMonths(8) + "</EndDate>");
        str.append("<PercentDone>0</PercentDone>");
        str.append("<ParentId/>");
        str.append("<IsLeaf>false</IsLeaf>");
        str.append("<Responsible>" + project.getOwner().getFullName() + "</Responsible>");
        str.append("</Task>");
        for (Task task : tasks) {
            start = new DateTime(task.getDueDate());
            str.append("<Task>");
            str.append("<Id>" + task.getTaskId() + "</Id>");
            str.append("<Name>" + task.getName() + "</Name>");
            str.append("<StartDate>" + start.withTime(0, 0, 0, 0).toString() + "</StartDate>");
            str.append("<EndDate>" + start.withTime(start.hourOfDay().getMaximumValue(), 59, 59, 59).toString() + "</EndDate>");
            str.append("<PercentDone>0</PercentDone>");
            str.append("<ParentId>1</ParentId>");
            str.append("<IsLeaf>true</IsLeaf>");
            str.append("<Responsible>" + task.getAssignee().getFullName() + "</Responsible>");
            str.append("</Task>");
        }
        str.append("</Tasks>'");
        return str.toString();
    }

    /**
     * Returns the contents of the given resource.
     * @param location The resource path.
     * @return The resource's content.
     * @throws FileNotFoundException If the resource cannot be found.
     * @throws IOException If anything goes wrong while reading the resource.
     */
    private static String getResourceContents(Class<?> clazz, String location) throws IOException {
        InputStream in = clazz.getResourceAsStream(location);
        if (in == null)
            throw new FileNotFoundException("'" + location + "' not found.");
        return getStreamContents(new InputStreamReader(in));
    }

    /**
     * Returns the complete content of the given stream.
     * @throws IOException If anything goes wrong while reading the stream.
     */
    private static String getStreamContents(InputStreamReader inputStreamReader) throws IOException {
        StringBuffer str = new StringBuffer();
        BufferedReader in = new BufferedReader(inputStreamReader);

        while (true) {
            String line = in.readLine();
            if (line == null)
                break;
            str.append(line);
            str.append("\n");
        }

        return str.toString();
    }

}
